import 'dart:ui' show LineMetrics;

import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:lib_uikit/lib_uikit.dart';


class GTEllipsisV3 extends StatefulWidget {
  final String text;

  /// 最少展示几行-在收起的状态下展示几行
  final int? minLines;

  /// 最多展示几行-在展开的状态下展示几行，
  /// 默认最多支持显示99行，要显示更多的行数需要手动传入
  final int? maxLines;

  /// 展开 文案
  final String? expandText;

  /// 收起 文案
  final String? shrinkText;

  /// 点击收起回调
  final Function? onExpand;

  /// 点击展开回调
  final Function? onShrink;

  /// 结尾按钮是否始终处于显示状态
  final bool? isAlwaysDisplay;

  const GTEllipsisV3({
    super.key,
    required this.text,
    this.minLines,
    this.maxLines,
    this.expandText,
    this.shrinkText,
    this.onExpand,
    this.onShrink,
    this.isAlwaysDisplay = true,
  });

  @override
  _GTEllipsisV3State createState() => _GTEllipsisV3State();
}

class _GTEllipsisV3State extends State<GTEllipsisV3> {
  final GlobalKey _key = GlobalKey();
  bool _isExpand = false;
  bool _isOver = false;
  late String _shrinkText;
  late String _expandText;
  @override
  void initState() {
    init();
    super.initState();
  }

  @override
  void dispose() {
    _key.currentState?.dispose();
    super.dispose();
  }

  @override
  void didUpdateWidget(GTEllipsisV3 oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.text.compareTo(oldWidget.text) != 0) {
      init();
    }
  }

  void init() {
    _shrinkText = widget.text.replaceAll('\n', '');
    _expandText = widget.text;
    if (widget.minLines != null && (widget.minLines??0) > 0) {
      initValue();
    }
  }

  String get _activeText => _isExpand ? _expandBtnText : _shrinkBtnText;

  String get _showText => _isExpand ? _expandText : _shrinkText;

  int get _minLines => _isExpand ? _maxLines : widget.minLines??0;

  int get _maxLines => widget.maxLines ?? 99;

  bool _isOverflow(List metrics, int len) => metrics.length > len;

  String get _shrinkBtnText => ' ${widget.expandText}';
  String get _expandBtnText => ' ${widget.shrinkText}';

  TextStyle get _textStyle =>
      DefaultTextStyle.of(context).style.merge(gtTextStyleW400(fontSize: 14,color: GTColorsV3.text1.color));

  void initValue() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final RenderBox renderBox = context.findRenderObject() as RenderBox;
      final maxWidth = renderBox.size.width;

      List<LineMetrics> lineMetrics = _paintText(widget.text, maxWidth: maxWidth);

      if (mounted) {
        setState(() {
          _isOver = _isOverflow(lineMetrics, widget.minLines ?? 0);
          if (_isOver) {
            _shrinkText = _calcShrinkText(lineMetrics, widget.minLines ?? 0, _shrinkBtnText,
                // maxWidth: maxWidth
            );
            _expandText = _calcShrinkText(
              lineMetrics,
              _maxLines,
              _expandBtnText,
              isExpand: true,
              // maxWidth: maxWidth
            );
          }
        });
      }
    });
  }

  List<LineMetrics> _paintText(String text, {double? maxWidth}) {
    final textPainter = TextPainter(
      textDirection: TextDirection.ltr,
      text: TextSpan(text: text, style: _textStyle),
    );
    if (maxWidth != null) {
      textPainter.layout(minWidth: maxWidth, maxWidth: maxWidth);
    } else {
      final textWidth = _key.currentContext?.size?.width;
      textPainter.layout(minWidth: textWidth??0, maxWidth: textWidth??0);
    }

    return textPainter.computeLineMetrics();
  }

  bool _lenEquals(String text, int len) => _paintText(text).length == len;

  void _tapRecognizer() {
    setState(() => _isExpand = !_isExpand);
    if (_isExpand) {
      (widget.onExpand ?? () => {})();
    } else {
      (widget.onShrink ?? () => {})();
    }
  }

  String _getOverflowedText(
      String shrinkText, {
        String trailingText = '',
        int limitLen = 0,
      }) {
    int textLen = widget.text.length;
    int step = 1;
    int count = 0;
    while (!_lenEquals('$shrinkText$trailingText', limitLen + 1)) {
      if (shrinkText.length + step > textLen) {
        count++;
        if (count > 10) {
          // 死循环检测处理
          break;
        }
        if (step < 1) {
          break;
        } else {
          step = step ~/ 2;
        }
      } else {
        shrinkText =_shrinkText.substring(0, shrinkText.length + step);
        step += 4;
      }
    }
    return shrinkText;
  }

  String _calcShrinkText(
      List<LineMetrics> lineMetrics,
      int len,
      String trailingBtnText, {
        bool isExpand = false,
      }) {
    // 如果限制的最大行数超过了实际渲染出来的最大行数，说明根据不会出现溢出的情况
    if (len > lineMetrics.length) return widget.text;

    final String spacerText = _isOverflow(lineMetrics, len) ? '...' : '';

    String trailingText;
    trailingText = '$spacerText$trailingBtnText';

    String shrinkText = '';
    // 下面加上结尾字符不一定会换行，因为字体不是等宽字体
    // 所以需要先确定溢出才开始倒算
    shrinkText = _getOverflowedText(
      shrinkText,
      trailingText: trailingText,
      limitLen: len,
    );
    // 这个时候这些文字加上结尾附加文字一定是会换行的
    // 所以一直判断如果文字换行的行数大于传入的指定行数，那么就从文字末尾减去一个字符
    // 再继续判断，直到文本行数等于传入的指定行数为止
    int offset = 0;
    while (!_lenEquals(shrinkText + trailingText, len)) {
      if (shrinkText.length - offset > 0) {
        offset++;
        shrinkText = shrinkText.substring(0, shrinkText.length - offset);
      } else {
        break;
      }
    }
    return '$shrinkText$spacerText';
  }

  InlineSpan _trailingBtn() {
    return TextSpan(
      text: _activeText,
      style: _textStyle.copyWith(color: GTColorsV3.text5.color),
      recognizer: TapGestureRecognizer()..onTap = _tapRecognizer,
    );
  }

  Widget _handleText() {
    return Stack(
      children: [
        Text.rich(
          TextSpan(
            text: _showText,
            children: [
              if (_isOver || (widget.isAlwaysDisplay??true)) _trailingBtn(),
            ],
          ),
          key: _key,
          maxLines: _minLines,
          softWrap: true,
          overflow: TextOverflow.ellipsis,
          style: _textStyle,
        ),
      ],
    );
  }

  Widget _dispatch() {
    if (widget.minLines != null && (widget.minLines??0) > 0) {
      return _handleText();
    }
    return Text(
      widget.text,
      maxLines: widget.minLines,
      style: _textStyle,
    );
  }

  @override
  Widget build(BuildContext context) {
    return _dispatch();
  }
}